home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / othergnu / texinf~1.zoo / texinfo.st / texi2roff / translate.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-12  |  10.9 KB  |  457 lines

  1. /*
  2.  * translate.c - main guts of texi2roff
  3.  *         Release 1.0a    August 1988
  4.  *        Release 2.0    January 1990
  5.  *
  6.  * Copyright 1988, 1989, 1990  Beverly A.Erlebacher
  7.  * erlebach@cs.toronto.edu    ...uunet!utai!erlebach
  8.  *
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include "texi2roff.h"
  13.  
  14. extern int transparent;        /* -t flag: dont discard things       */
  15. int    displaylevel = 0;    /* nesting level of 'display' text */
  16. int    inmacroarg = NO;    /* protect roff macro args flag */
  17. int     ilevel = 0;        /* nesting level of itemized lists */
  18. int    linecount;
  19. char    *filename;
  20. char     *inp;            /* pointer into input buffer */
  21.  
  22. extern struct tablerecd * lookup();
  23.  
  24. /* forward references */
  25. extern char * gettoken();
  26. extern char * eatwhitespace();
  27. extern char * itemize();
  28. extern char * doitem();
  29. extern char * interpret();
  30.  
  31. /*
  32.  * errormsg - print error messages to stderr
  33.  */
  34.  
  35. void
  36. errormsg( message, other)
  37.     char       *message;
  38.     char       *other;
  39. {
  40.     (void) fprintf(stderr, "%s line %d : %s%s\n",
  41.     filename, linecount, message, other);
  42. }
  43.  
  44. /*
  45.  * translate - translate one Texinfo file
  46.  */
  47.  
  48. int 
  49. translate(in, inname)
  50.     FILE       *in;
  51.     char       *inname;
  52. {
  53.     char       input[MAXLINELEN];
  54.     char       output[MAXLINELEN * 2];
  55.     char       token[MAXLINELEN];
  56.     char       *c, *cprev;
  57.     static char       lastchar;
  58.     int           savlinct;
  59.     char       *savfilnam;
  60.  
  61.     /*
  62.      * save global variables linecount and filename in case this is a
  63.      * recursive call to translate an @include file.  these variables
  64.      * are used by errormsg() which is called from many places.
  65.      */
  66.     savfilnam = filename;
  67.     savlinct = linecount;
  68.        
  69.     filename = inname;
  70.     linecount = 0;
  71.     lastchar = '\n';
  72.  
  73.     /*
  74.      * if fgets() truncates a line in the middle of a token, a blank will
  75.      * appear in the word containing the MAXLINELENth char in the absurdly
  76.      * long line. this is handled by gettoken()
  77.      */
  78.  
  79.     while (fgets(input, MAXLINELEN, in) != NULL) {
  80.     ++linecount;
  81.     inp = input;
  82.     *output = 0;
  83.     if (*inp == '.')        /* protect leading '.' in input */
  84.         (void) strcpy(output, "\\&");
  85.     else if (*inp == '\n') {
  86.         if (displaylevel > 0)
  87.         (void) strcat(output,"\\&\n");      /* protect newline */
  88.         else if (ilevel > 0)    /* indented paragraph */
  89.         (void) strcat(output, cmds->dfltipara);
  90.         else            /* default paragraph */
  91.         (void) strcat(output,cmds->dfltpara);
  92.     }
  93.     while (*inp != '\0') {
  94.         inp = gettoken(inp, token);
  95.         inp = interpret(token, output);
  96.         if (inp == NULL)
  97.         return ERROR;
  98.     }
  99.  
  100.     /*
  101.      * output, stripping surplus newlines when possible. 
  102.      * protect lines starting with ' or \ by adding leading \&.
  103.      */
  104.     cprev = &lastchar;   /* character at end of previous output buffer */
  105.     for( c = output; *c != '\0'; cprev = c, ++c) {
  106.         if (*c != '\n' || *cprev != '\n') {
  107.         if ( *cprev == '\n' && (*c == '\\' || *c == '\''))
  108.             (void) fputs("\\&", stdout);
  109.         (void) putc(*c, stdout);
  110.         }
  111.     }
  112.     lastchar = *cprev;
  113.     }
  114.     /* restore the globals */
  115.     filename = savfilnam;
  116.     linecount = savlinct;
  117.     return 0;
  118. }
  119.  
  120. /*
  121.  * PUSH - macro to push pointer to table entry onto command stack
  122.  *      and current font onto font stack
  123.  */
  124.  
  125. #define MAXDEPTH    20
  126.  
  127. #define PUSH(tptr)                            \
  128.     if (++stackptr == MAXDEPTH) {                    \
  129.     errormsg("stack overflow - commands nested too deeply", "");    \
  130.     return NULL;                            \
  131.     }                                    \
  132.     stack[stackptr] = tptr;                        \
  133.     (void) strcpy(fontstack[++fontptr], curfont);            \
  134.     if (*tptr->font != '\0')                         \
  135.     (void) strcpy(curfont, tptr->font);                
  136.  
  137.  
  138. /*
  139.  * interpret - interprets and concatenates interpreted token onto outstring
  140.  */
  141.  
  142. char *
  143. interpret(token, outstring)
  144. char    *token;
  145. char    *outstring;
  146. {
  147.     static struct tablerecd *stack[MAXDEPTH];
  148.     static int        stackptr = 0; /* zeroth element is not used */
  149.     static int      discarding = NO;
  150.     static int        discardlevel = MAXDEPTH;
  151.     static int        fontptr;
  152. /* large enough for "\\fR\\&\\f(CW" */
  153. #define FONTSTRSIZE 12
  154.     static char        fontstack[MAXDEPTH][FONTSTRSIZE];
  155.     static char        curfont[FONTSTRSIZE];
  156.     static char        defaultfont[] = "\\fR";
  157.     static int        init = NO;
  158.     struct tablerecd *tptr;
  159.     char        *s, *cp, tempstr[MAXLINELEN],itemtag[MAXLINELEN];
  160.     FILE        *fp;    /* for @include files */
  161.     extern int        process();    /* for @include files */
  162.  
  163.     if (init == NO) {
  164.     (void) strcpy(fontstack[0], defaultfont);
  165.     (void) strcpy(curfont, defaultfont);
  166.     fontptr = 0;
  167.     init = YES;
  168.     }
  169.     s = inp;
  170.     if (stackptr > 0 && STREQ(token, stack[stackptr]->texend)) {
  171.     /* have fetched closing token of current Texinfo command */
  172.     if (STREQ(token, "@end")) {/* WARNING! only works from translate() */
  173.         s = gettoken(eatwhitespace(s),tempstr);
  174.         if    (! STREQ(&(stack[stackptr]->texstart[1]), tempstr) 
  175.                 && !discarding) {
  176.         errormsg("unexpected @end found for Texinfo cmd @", tempstr);
  177.         return s;
  178.         }
  179.     }
  180.     if (!discarding)
  181.         (void) strcat(outstring, stack[stackptr]->trfend);
  182.     
  183.     /* restore previous active font */
  184.     if (STREQ(curfont, fontstack[fontptr]) == NO) {
  185.         (void) strcpy(curfont, fontstack[fontptr]);
  186.         (void) strcat(outstring, curfont);
  187.     }
  188.     if (fontptr > 0)
  189.         --fontptr;
  190.  
  191.     if (stack[stackptr]->type == DISPLAY)
  192.         --displaylevel;
  193.     else if (stack[stackptr]->type == ITEMIZING) {
  194.         --ilevel;
  195.         if (!discarding && ilevel > 0)
  196.         (void) strcat(outstring, cmds->indentend);
  197.     }
  198.  
  199.     if (--stackptr < 0) {
  200.         errormsg("stack underflow", "");
  201.         return NULL;
  202.     }
  203.         if (discarding && stackptr < discardlevel) {
  204.         discarding = NO;
  205.         discardlevel = MAXDEPTH;
  206.         }
  207.     if (*token == '\n' || STREQ(token, "@end")) {
  208.         inmacroarg = NO;
  209.         return "";          /* flush rest of line if any */
  210.     }
  211.     } else if (*token != '@') {     /* ordinary piece of text */
  212.     if (!discarding)
  213.         (void) strcat(outstring, token);
  214.     if (*token == '\n') {
  215.         inmacroarg = NO;
  216.         return "";
  217.     }
  218.     } else {                /* start of Texinfo command */
  219.     if ((tptr = lookup(token)) == NULL){
  220.         if (!discarding)
  221.         errormsg("unrecognized Texinfo command ", token);
  222.     } else {
  223.         switch (tptr->type) {
  224.         case ESCAPED:
  225.         if (!discarding)
  226.             (void) strcat(outstring, tptr->trfstart);
  227.         break;
  228.         case DISPLAY:
  229.         ++displaylevel;
  230.         PUSH(tptr);
  231.         if (!discarding)
  232.             (void) strcat(outstring, tptr->trfstart);
  233.         break;
  234.         case HEADING:
  235.         inmacroarg = YES;   /* protect ',", space in hdr macro args */
  236.         /* fall through */
  237.         case INDEX:
  238.         s = eatwhitespace(s);
  239.         /* fall through */
  240.         case CHAR:    /* may be some need to distinguish these 3 in future */
  241.         case INPARA:
  242.         case PARAGRAPH:
  243.         PUSH(tptr);
  244.         if (!discarding)
  245.             (void) strcat(outstring, tptr->trfstart);
  246.         break;
  247.         case DISCARD:
  248.         PUSH(tptr);
  249.         if (!discarding && !transparent) {
  250.             discarding = YES;
  251.             discardlevel = stackptr;
  252.         }
  253.         break;
  254.         case ITEMIZING:
  255.         if (!discarding) {
  256.             (void) strcat(outstring, tptr->trfstart);
  257.             if (ilevel > 0)
  258.             (void) strcat(outstring, cmds->indentstart);
  259.         }
  260.         PUSH(tptr);
  261.         ++ilevel;
  262.         s = itemize(s, token);
  263.         break;
  264.         case ITEM:
  265.         PUSH(tptr);
  266.         if (!discarding) {
  267.             (void) strcat(outstring, tptr->trfstart);
  268.             inmacroarg = YES;
  269.             /* set up, parse and interpret item tag */
  270.             s = doitem(eatwhitespace(s),itemtag);
  271.             cp = itemtag;
  272.             while (*cp != '\n' && *cp != '\0') {
  273.             cp = gettoken(cp, tempstr);
  274.             (void) interpret(tempstr, outstring);
  275.             }
  276.         }
  277.         break;
  278.         case END:
  279.         s = gettoken(eatwhitespace(s),tempstr);
  280.         if (!discarding) 
  281.          errormsg("unexpected @end found for Texinfo cmd @", tempstr);
  282.         break;
  283.         case FOOTNOTE:
  284.         PUSH(tptr);
  285.         if (!discarding) {
  286.             s = gettoken(eatwhitespace(s),tempstr);
  287.             cp = outstring + strlen(outstring);
  288.             (void) interpret(tempstr, outstring);
  289.             (void) strcpy(tempstr, cp);
  290.             (void) strcat(outstring, tptr->trfstart);
  291.             /* replicate footnote mark */
  292.             (void) strcat(outstring, tempstr);
  293.         }
  294.         break;
  295.         case INCLUDE:
  296.         s = eatwhitespace(s);
  297.         for (cp = tempstr; strchr(" \t\n",*s) == NULL; *cp++ = *s++)
  298.             ;
  299.         *cp = '\0';
  300.         if (!discarding && ( fp = fopen(tempstr, "r")) == NULL)
  301.             errormsg("can't open included file ", tempstr);
  302.         else {
  303.             (void) process(fp, tempstr);
  304.             (void) fclose(fp);
  305.         }
  306.         break;
  307.         default:
  308.         /* can't happen */
  309.         errormsg("ack ptui, what was that thing? ", token);
  310.         }
  311.     }
  312.     }
  313.     return s;
  314. }    
  315.  
  316. /*
  317.  * eatwhitespace - move input pointer to first char that isnt a blank or tab
  318.  *    (note that newlines are *not* whitespace)
  319.  */
  320.  
  321. char           *
  322. eatwhitespace(s)
  323.     register char       *s;
  324. {
  325.     while(*s == ' ' || *s == '\t')
  326.     ++s ;
  327.     return s;
  328. }
  329.  
  330.  
  331. /* 
  332.  * strpbrk_like - returns pointer to the leftmost occurrence in str of any
  333.  *    character in set, else pointer to terminating null. 
  334. */
  335.  
  336. char *
  337. strpbrk_like(str, set)
  338.     register char *str;
  339.     char *set;
  340. {
  341.     static int inited_set = 0;
  342.     static char set_vec[256] = { 0 };
  343.  
  344.     if (!inited_set) {    /* we *know* it'll be the same every time... */
  345.     while (*set)
  346.          set_vec[(unsigned char)*set++] = 1;
  347.     set_vec[0] = 1;
  348.     inited_set = 1;
  349.     }
  350.     while (set_vec[*str] == 0)
  351.     ++str;
  352.     return str;
  353. }
  354.  
  355.  
  356. /*
  357.  * gettoken - fetch next token from input buffer. leave the input pointer
  358.  *    pointing to char after token.     may need to be modified when 
  359.  *    new Texinfo commands are added which use different token boundaries.
  360.  *
  361.  *    will handle case where fgets() has split a long line in the middle
  362.  *    of a token, but the token will appear to have been divided by a blank
  363.  */
  364.  
  365. char           *
  366. gettoken(s, token)
  367.     char       *s;
  368.     char       *token;
  369. {
  370.     static char       endchars[] = " \n\t@{}:.*";
  371.     static char    singlequote[] = "\\(fm";
  372.     static char    doublequote[] = "\\(pd";
  373.     char       *q, *t;
  374.  
  375.     q = s;
  376.     s = strpbrk_like(q, endchars);
  377.     if (s != q) {
  378.     switch (*s) {
  379.     case ' ':
  380.     case '\n':
  381.     case '\t':
  382.     case '@':
  383.     case '}':
  384.     case ':':
  385.     case '.':
  386.     case '*':
  387.     case '\0':
  388.         --s;
  389.         break;
  390.     case '{':
  391.         break;
  392.     }
  393.     } else {    /* *s == *q */
  394.     switch (*s) {
  395.     case ' ':
  396.     case '\n':
  397.     case '\t':
  398.     case '{':
  399.     case ':':
  400.     case '.':
  401.     case '*':
  402.     case '\0':
  403.         break;
  404.     case '}':
  405.         if (*(s+1) == '{') /* footnotes with daggers and dbl daggers!! */
  406.         ++s;
  407.         break;
  408.     case '@':
  409.         s = strpbrk_like(q + 1, endchars );
  410.         /* handles 2 char @ tokens: @{ @} @@ @: @. @* */
  411.         if ( strchr("{}@:.*", *s) == NULL
  412.             || (s > q+1 && (*s =='}' || *s == '@')))
  413.         --s;
  414.         break;
  415.     }
  416.     }
  417.     for (t = token; q <= s; ++q, ++t) {
  418.     switch (*q) {
  419.         case '\\' :         /* replace literal \ with \e */
  420.         *t = *q;
  421.         *++t = 'e';
  422.         break;
  423.         case ' '  :        /* protect spaces in macro args */
  424.         if (inmacroarg == YES) {
  425.             *t = '\\';
  426.             *++t = *q;
  427.         } else
  428.             *t = *q;
  429.         break;
  430.         case '\'' :        /* convert ' to footmark in macro args */
  431.         if (inmacroarg == YES) {
  432.             *t = 0;
  433.             (void) strcat(t,singlequote);
  434.             t += strlen(singlequote) - 1;
  435.         } else
  436.             *t = *q;
  437.         break;
  438.         case '\"' :        /* try to avoid " trouble in macro args */
  439.         if (inmacroarg == YES) {
  440.             *t = 0;
  441.             (void) strcat(t,doublequote);
  442.             t += strlen(doublequote) - 1;
  443.         } else
  444.             *t = *q;
  445.         break;
  446.         case '\0':
  447.         *t = ' ';
  448.         break;
  449.         default   :
  450.         *t = *q;
  451.         break;
  452.     }
  453.     }
  454.     *t = 0;
  455.     return ++s;
  456. }
  457.